package com.cmc.cloud.cmclink.doc.service.impl.so;

import cn.hutool.core.collection.CollectionUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.cmc.cloud.cmclink.bdt.api.base.VesselDataApi;
import com.cmc.cloud.cmclink.bdt.api.base.dto.req.VesselNameListByCodeReqDTO;
import com.cmc.cloud.cmclink.bdt.api.base.dto.resp.VesselNameDataRespDTO;
import com.cmc.cloud.cmclink.doc.api.document.emums.*;
import com.cmc.cloud.cmclink.doc.constants.errorconstant.SoErrorCodeConstants;
import com.cmc.cloud.cmclink.doc.convert.SoConvert;
import com.cmc.cloud.cmclink.doc.convert.SoVslvoyConvert;
import com.cmc.cloud.cmclink.doc.entity.SoDO;
import com.cmc.cloud.cmclink.doc.entity.SoVslvoyDO;
import com.cmc.cloud.cmclink.doc.mapper.SoMapper;
import com.cmc.cloud.cmclink.doc.mapper.SoVslvoyMapper;
import com.cmc.cloud.cmclink.doc.service.so.SoService;
import com.cmc.cloud.cmclink.doc.vo.manifestvo.manifest.ManifestSoPageReqVO;
import com.cmc.cloud.cmclink.doc.vo.sovo.sovo.*;
import com.cmc.cloud.cmclink.doc.vo.sovo.sovslvoyvo.SoVslvoyUpdateReqVO;
import com.cmes.framework.common.exception.ErrorCode;
import com.cmes.framework.common.exception.util.ServiceExceptionUtil;
import com.cmes.framework.common.pojo.CommonResult;
import com.cmes.framework.common.pojo.PageResult;
import com.cmes.framework.mybatis.core.query.LambdaQueryWrapperX;
import com.cmes.framework.security.core.util.SecurityFrameworkUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.validation.annotation.Validated;

import javax.annotation.Resource;
import java.time.LocalDateTime;
import java.util.*;
import java.util.stream.Collectors;


/**
 * 订舱主 Service 实现类
 *
 * @author 招商轮船-管理员
 */
@Service
@Validated
public class SoServiceImpl implements SoService {
    public static String PREVIOUS = "Previous";
    public static String NEXT = "Next";
    @Resource
    private SoMapper soMapper;
    @Resource
    private SoVslvoyMapper soVslvoyMapper;

    @Resource
    VesselDataApi vesselDataApi;

    @Override
    public SoDO createSo(SoCreateReqVO createReqVO) {
        // 插入
        SoDO so = SoConvert.INSTANCE.convert(createReqVO);
        // 默认状态
        setDefaultDraftValue(so);
        soMapper.insert(so);
        return so;
    }

    @Override
    public SoDO createOrUpdateSo(SoUpdateReqVO createReqVO) {
        // 插入
        SoDO so = SoConvert.INSTANCE.convert(createReqVO);
        if (createReqVO.getId() != null) {
            validateSoExists(createReqVO.getId());
            soMapper.updateById(so);
        } else {
            // 默认状态
            setDefaultDraftValue(so);
            soMapper.insert(so);
        }
        return so;
    }


    @Override
    public void updateSo(SoUpdateReqVO updateReqVO) {
        // 校验存在
        validateSoExists(updateReqVO.getId());
        // 更新
        SoDO updateObj = SoConvert.INSTANCE.convert(updateReqVO);
        soMapper.updateById(updateObj);
    }

    @Override
    public void updateById(SoDO updateObj) {
        updateObj.setUpdateTime(LocalDateTime.now());
        updateObj.setUpdater(String.valueOf(SecurityFrameworkUtils.getLoginUserId()));
        soMapper.updateById(updateObj);
    }

    @Override
    public void deleteSo(Long id) {
        // 校验存在
        validateSoExists(id);
        // 删除
        soMapper.deleteById(id);
    }

    private void validateSoExists(Long id) {
        if (soMapper.selectById(id) == null) {
            throw ServiceExceptionUtil.exception(SoErrorCodeConstants.SO_NOT_EXISTS);
        }
    }

    @Override
    public SoDO getSo(Long id) {
        return soMapper.selectById(id);
    }

    @Override
    public Long findPreviousOrNext(Long id, String type) {
        LambdaQueryWrapperX<SoDO> queryWrapperX = new LambdaQueryWrapperX<SoDO>();
        if (PREVIOUS.equals(type)) {
            queryWrapperX.le(SoDO::getId, id);
        } else {
            queryWrapperX.gt(SoDO::getId, id);
        }
        queryWrapperX.last("LIMIT 1");
        SoDO temp = soMapper.selectOne(queryWrapperX);
        if (temp != null) {
            return temp.getId();
        }
        return null;
    }

    @Override
    public Long getByBookingNoOrBlNo(SoQueryReqVO req) {
        if (StringUtils.isEmpty(req.getBookingNo()) && StringUtils.isEmpty(req.getBlNo())) {
            throw ServiceExceptionUtil.exception(SoErrorCodeConstants.SO_NOT_EXISTS);
        }
        LambdaQueryWrapperX<SoDO> queryWrapperX = new LambdaQueryWrapperX<SoDO>();
        queryWrapperX.eqIfPresent(SoDO::getBookingNo, req.getBookingNo());
        queryWrapperX.eqIfPresent(SoDO::getBlNo, req.getBlNo());
        queryWrapperX.eq(SoDO::getValidStatus, 1);
        queryWrapperX.last("LIMIT 1");
        SoDO temp = soMapper.selectOne(queryWrapperX);
        if (temp != null) {
            return temp.getId();
        }
        throw ServiceExceptionUtil.exception(SoErrorCodeConstants.SO_NOT_EXISTS);
    }
    @Override
    public SoDO ediGetByBookingNoOrBlNo(SoQueryReqVO req) {
        if (StringUtils.isEmpty(req.getBookingNo()) && StringUtils.isEmpty(req.getBlNo())) {
            throw ServiceExceptionUtil.exception(SoErrorCodeConstants.SO_NOT_EXISTS);
        }
        LambdaQueryWrapperX<SoDO> queryWrapperX = new LambdaQueryWrapperX<SoDO>();
        queryWrapperX.eqIfPresent(SoDO::getBookingNo, req.getBookingNo());
        queryWrapperX.eqIfPresent(SoDO::getBlNo, req.getBlNo());
        queryWrapperX.eq(SoDO::getValidStatus, 1);
        queryWrapperX.last("LIMIT 1");
        return soMapper.selectOne(queryWrapperX);
    }

    @Override
    public SoDO getSoDoByBookingNoOrBlNo(SoQueryReqVO req) {
        if (StringUtils.isEmpty(req.getBookingNo()) && StringUtils.isEmpty(req.getBlNo())) {
            throw ServiceExceptionUtil.exception(SoErrorCodeConstants.SO_NOT_EXISTS);
        }
        LambdaQueryWrapperX<SoDO> queryWrapperX = new LambdaQueryWrapperX<SoDO>();
        queryWrapperX.eqIfPresent(SoDO::getBookingNo, req.getBookingNo());
        queryWrapperX.eqIfPresent(SoDO::getBlNo, req.getBlNo());
        queryWrapperX.eq(SoDO::getValidStatus, 1);
        queryWrapperX.last("LIMIT 1");
        SoDO temp = soMapper.selectOne(queryWrapperX);
        if (temp != null) {
            return temp;
        }
        throw ServiceExceptionUtil.exception(SoErrorCodeConstants.SO_NOT_EXISTS);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void updateVoyageInfo(String bookingNo, List<SoVslvoyUpdateReqVO> voyageInfo) {
        if (StringUtils.isEmpty(bookingNo) || CollectionUtil.isEmpty(voyageInfo)) {
            return;
        }
        SoDO so = getSoDoByBookingNoOrBlNo(new SoQueryReqVO(bookingNo, null, null));
        LambdaQueryWrapperX<SoVslvoyDO> voyageWrapper = new LambdaQueryWrapperX<>();
        voyageWrapper.eq(SoVslvoyDO::getSoId, so.getId());
        soVslvoyMapper.delete(voyageWrapper);
        //同步航线信息
        syncSo(voyageInfo, so);
        soMapper.updateById(so);
        List<SoVslvoyDO> soVslvoyList = SoVslvoyConvert.INSTANCE.convertBatchUpdate(voyageInfo);
        soVslvoyList.forEach(voyageDo -> {
            voyageDo.setId(null);
            voyageDo.setSoId(so.getId());
            voyageDo.setSpaceApproveStatus(ApproveStatusEnum.APPROVED.getValue());
        });
        soVslvoyMapper.insertBatch(soVslvoyList);
    }

    public void syncSo(List<SoVslvoyUpdateReqVO> soVslvoyList, SoDO so) {
        // 新增修改时 业务校验 自动填充数据
        SoVslvoyUpdateReqVO vslvoyLineFirst = null;
        if (CollectionUtil.isNotEmpty(soVslvoyList)) {
            List<String> vesselCodeList = soVslvoyList.stream().map(e -> e.getVesselCode()).collect(Collectors.toList());
            Map<String, String> vesselOperatorMap = getVesselOperatorByCodes(vesselCodeList);
            StringBuilder routeDescription = new StringBuilder();
            for (int i = 0; i < soVslvoyList.size(); i++) {
                SoVslvoyUpdateReqVO temp = soVslvoyList.get(i);
                temp.setVesselOperator(vesselOperatorMap.get(temp.getVesselCode()));
                // 装货港与上一段卸货港要相同
                if (i - 1 >= 0) {
                    if (!soVslvoyList.get(i).getPolCode().equals(soVslvoyList.get(i - 1).getPodCode())) {
                        throw ServiceExceptionUtil.exception(SoErrorCodeConstants.SO_LINER_POL_POD_CONFLICT);
                    }
                }
                //根据SO的Voyageroute 里的第一个liner段设置
                if (TransmodeEnum.LINER.getValue().equals(temp.getTransmode())) {
                    if (vslvoyLineFirst == null) {
                        vslvoyLineFirst = temp;
                    }
                } else {
                    // 多式联运设置默认值 TBA
                    setDefaultTba(temp);
                }
                temp.setRouteNo(i + 1);

                //拼接各个航段 Route：CNSHA-(LINER)-JYTPO-(LINER)-AUSYD
                if (i == 0) {
                    routeDescription.append(temp.getPolCode());
                    routeDescription.append("-(").append(temp.getTransmode()).append(")-");
                    routeDescription.append(temp.getPodCode());
                    so.setPorCode(temp.getPolCode());
                } else {
                    routeDescription.append("-(").append(temp.getTransmode()).append(")-");
                    routeDescription.append(temp.getPodCode());
                    if (i == soVslvoyList.size() - 1) {
                        so.setDelCode(temp.getPodCode());
                    }
                }
            }
            if (vslvoyLineFirst == null) {
                throw ServiceExceptionUtil.exception(SoErrorCodeConstants.SO_NO_LINER);
            }
            // line 的第一个
            so.setPolCode(vslvoyLineFirst.getPolCode());
            so.setPodCode(vslvoyLineFirst.getPodCode());
            if (vslvoyLineFirst != null) {
                so.setBookingVessel(vslvoyLineFirst.getVesselCode());
                so.setBookingVoyage(vslvoyLineFirst.getVoyageEx());
                so.setCurrentPort(vslvoyLineFirst.getPolCode());
            }
            so.setRouteDescription(routeDescription.toString());
        }
    }

    public Map<String, String> getVesselOperatorByCodes(List<String> vesselCodeList) {
        //通过船名编码 获取船的详细信息
        Map<String, String> vesselOperatorMap = new HashMap<>(32);
        VesselNameListByCodeReqDTO codeReq = new VesselNameListByCodeReqDTO();
        codeReq.setVesselCodeList(vesselCodeList);
        CommonResult<List<VesselNameDataRespDTO>> result = vesselDataApi.listByCodeList(codeReq);
        if (result != null && CollectionUtil.isNotEmpty(result.getData())) {
            return result.getData().stream().filter(e -> StringUtils.isNotEmpty(e.getVesselOperator())).collect(Collectors.toMap(VesselNameDataRespDTO::getVesselCode, VesselNameDataRespDTO::getVesselOperator));
        }
        return vesselOperatorMap;
    }

    public void setDefaultTba(SoVslvoyUpdateReqVO vslvoy) {
        if (StringUtils.isEmpty(vslvoy.getVesselCode())) {
            vslvoy.setLaneCodeEx("TBA");
            vslvoy.setLaneCodeIm("TBA");
            vslvoy.setVoyageEx("TBA");
            vslvoy.setVoyageIm("TBA");
            vslvoy.setVesselCode("TBA");
        }
    }

    @Override
    public List<SoDO> getSoList(Collection<Long> ids) {
        return soMapper.selectBatchIds(ids);
    }

    @Override
    public List<SoDO> getSoListByBlNos(List<String> blNos) {
        if (CollectionUtil.isNotEmpty(blNos)) {
            LambdaQueryWrapperX<SoDO> queryWrapperX = new LambdaQueryWrapperX<SoDO>();
            queryWrapperX.inIfPresent(SoDO::getBlNo, blNos);
            queryWrapperX.eq(SoDO::getValidStatus, 1);
            List<SoDO> soDos = soMapper.selectList(queryWrapperX);
            return soDos;
        } else {
            throw ServiceExceptionUtil.exception(SoErrorCodeConstants.SO_PARAM_ERROR);
        }
    }

    @Override
    public void updateBatch(Collection<SoDO> solist) {
        if (CollectionUtil.isEmpty(solist)) {
            return;
        }
        soMapper.updateBatch(solist);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void deleteBySoIds(Collection<Long> ids, String userId) {
        checkSoStatusByUserId(ids, Arrays.asList(SoStatusEnum.BookingDraft.getValue()), userId);
        //删除 草稿状态
        LambdaUpdateWrapper<SoDO> updateWrapper = new LambdaUpdateWrapper<>();
        updateWrapper.in(SoDO::getId, ids);
        updateWrapper.eq(SoDO::getSoStatus, SoStatusEnum.BookingDraft.getValue());
        soMapper.delete(updateWrapper);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void batchReturnToDraft(Collection<Long> ids) {
        //状态返回为草稿状态
        LambdaUpdateWrapper<SoDO> updateWrapper = new LambdaUpdateWrapper<>();
        updateWrapper.in(SoDO::getId, ids);
        updateWrapper.set(SoDO::getBookingTime, null);
        updateWrapper.set(SoDO::getProcessInstanceId, null);
        updateWrapper.set(SoDO::getOldId, null);
        updateWrapper.set(SoDO::getValidStatus, 1);
        updateWrapper.set(SoDO::getSoContentStatus, "");
        updateWrapper.set(SoDO::getSoStatus, SoStatusEnum.BookingDraft.getValue());
        updateWrapper.set(SoDO::getUpdater, String.valueOf(SecurityFrameworkUtils.getLoginUserId()));
        updateWrapper.set(SoDO::getUpdateTime, LocalDateTime.now());
        soMapper.update(null, updateWrapper);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void setCustomerUploadedMaterial(Long id) {
        //状态返回为草稿状态
        LambdaUpdateWrapper<SoDO> updateWrapper = new LambdaUpdateWrapper<>();
        updateWrapper.eq(SoDO::getId, id);
        updateWrapper.set(SoDO::getSoStatus, SoStatusEnum.CustomerUploadedMaterial.getValue());
        updateWrapper.set(SoDO::getSoContentStatus, SoContentStatusEnum.PENDING.getValue());
        updateWrapper.set(SoDO::getUpdater, String.valueOf(SecurityFrameworkUtils.getLoginUserId()));
        updateWrapper.set(SoDO::getUpdateTime, LocalDateTime.now());
        soMapper.update(null, updateWrapper);
    }

    @Override
    public void setDefaultDraftValue(SoDO so) {
        so.setBlNo(null);
        so.setBookingNo(null);
        so.setBookingTime(null);
        so.setProcessInstanceId(null);
        so.setOldId(null);
        so.setSoContentStatus(null);
        so.setValidStatus(ValidStatusEnum.DEFAULT_VALID.getValue());
        if (StringUtils.isEmpty(so.getDataSource())) {
            so.setDataSource(SoDataSourceEnum.MANUAL.getValue());
        }
        so.setSplitCombine(SoSplitCombineEnum.NORMAL.getValue());
        so.setSoStatus(SoStatusEnum.BookingDraft.getValue());
    }

    @Override
    public List<SoDO> checkSoStatusByUserId(Collection<Long> ids, List<String> soStatus, String userId) {
        return checkSoStatusByUserId(ids, soStatus, userId, null);
    }

    @Override
    public List<SoDO> checkSoStatusByUserId(Collection<Long> ids, List<String> soStatus, String userId, String errorMsg) {
        if (CollectionUtil.isEmpty(ids)) {
            throw ServiceExceptionUtil.exception(SoErrorCodeConstants.SO_NOT_EXISTS);
        }
        //查询状态，默认只能操作自己的
        LambdaQueryWrapperX<SoDO> queryWrapperX = new LambdaQueryWrapperX<SoDO>();
        queryWrapperX.in(SoDO::getId, ids);
        queryWrapperX.inIfPresent(SoDO::getSoStatus, soStatus);
        //queryWrapperX.eqIfPresent(SoDO::getCreator, userId);
        List<SoDO> list = soMapper.selectList(queryWrapperX);
        if (ids.size() != list.size()) {
            if (StringUtils.isNotEmpty(errorMsg)) {
                throw ServiceExceptionUtil.exception(new ErrorCode(SoErrorCodeConstants.SO_BOOKING_DRAFT_CHANGE.getCode(), errorMsg));
            } else {
                throw ServiceExceptionUtil.exception(SoErrorCodeConstants.SO_BOOKING_DRAFT_CHANGE);
            }
        }
        return list;
    }

    @Override
    public PageResult<SoDO> getSoPage(SoPageReqVO reqVO) {
        IPage<SoDO> page = Page.of(reqVO.getPageNo(), reqVO.getPageSize());
        if (reqVO.getBookingTimeEnd() != null) {
            // 默认结束时间包括当天
            reqVO.setBookingTimeEnd(reqVO.getBookingTimeEnd().plusDays(1));
        }
        if (reqVO.getCreateTimeEnd() != null) {
            // 默认结束时间包括当天
            reqVO.setCreateTimeEnd(reqVO.getCreateTimeEnd().plusDays(1));
        }
        // 不管用哪个航次查都显示第一程liner的船名航次。 第一程liner 冗余在主表
        IPage<SoDO> result = soMapper.selectPageList(page, reqVO);
        return new PageResult<SoDO>(result.getRecords(), result.getTotal());
    }

    @Override
    public PageResult<SoRespVO> getSoManifest(ManifestSoPageReqVO reqVO) {
        IPage<SoRespVO> page = Page.of(reqVO.getPageNo(), reqVO.getPageSize());
        if (reqVO.getBookingTimeEnd() != null) {
            // 默认结束时间包括当天
            reqVO.setBookingTimeEnd(reqVO.getBookingTimeEnd().plusDays(1));
        }
        if (reqVO.getCreateTimeEnd() != null) {
            // 默认结束时间包括当天
            reqVO.setCreateTimeEnd(reqVO.getCreateTimeEnd().plusDays(1));
        }
        // 不管用哪个航次查都显示第一程liner的船名航次。 第一程liner 冗余在主表
        IPage<SoRespVO> result = soMapper.getSoManifest(page, reqVO);
        return new PageResult<SoRespVO>(result.getRecords(), result.getTotal());
    }

    @Override
    public PageResult<SoRespVO> getSoPageAmend(SoPageReqVO reqVO) {
        IPage<SoRespVO> page = Page.of(reqVO.getPageNo(), reqVO.getPageSize());
        if (reqVO.getBookingTimeEnd() != null) {
            // 默认结束时间包括当天
            reqVO.setBookingTimeEnd(reqVO.getBookingTimeEnd().plusDays(1));
        }
        if (reqVO.getCreateTimeEnd() != null) {
            // 默认结束时间包括当天
            reqVO.setCreateTimeEnd(reqVO.getCreateTimeEnd().plusDays(1));
        }
        // 不管用哪个航次查都显示第一程liner的船名航次。 第一程liner 冗余在主表
        IPage<SoRespVO> result = soMapper.getSoPageAmend(page, reqVO);
        return new PageResult<SoRespVO>(result.getRecords(), result.getTotal());
    }


    @Override
    @Transactional(rollbackFor = Exception.class)
    public void updateStatusAndContentStatus(Long id, String soStatus, String soContentStatus) {
        //状态返回为草稿状态
        LambdaUpdateWrapper<SoDO> updateWrapper = new LambdaUpdateWrapper<>();
        updateWrapper.eq(SoDO::getId, id);
        updateWrapper.set(SoDO::getSoStatus, soStatus);
        updateWrapper.set(SoDO::getSoContentStatus, soContentStatus);
        updateWrapper.set(SoDO::getUpdater, String.valueOf(SecurityFrameworkUtils.getLoginUserId()));
        updateWrapper.set(SoDO::getUpdateTime, LocalDateTime.now());
        soMapper.update(null, updateWrapper);
    }


    @Override
    @Transactional(rollbackFor = Exception.class)
    public void updateValidStatus(List<Long> oldSoIds, Integer validStatus) {
        //状态返回为草稿状态
        LambdaUpdateWrapper<SoDO> updateWrapper = new LambdaUpdateWrapper<>();
        updateWrapper.in(SoDO::getId, oldSoIds);
        updateWrapper.set(SoDO::getValidStatus, validStatus);
        updateWrapper.set(SoDO::getUpdater, String.valueOf(SecurityFrameworkUtils.getLoginUserId()));
        updateWrapper.set(SoDO::getUpdateTime, LocalDateTime.now());
        soMapper.update(null, updateWrapper);
    }

    @Override
    public List<SoDO> queryList(SoListReqVO reqVO) {
        //状态返回为草稿状态
        LambdaQueryWrapper<SoDO> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.in(SoDO::getBookingNo, reqVO.getBookingNoList());
        queryWrapper.eq(SoDO::getBookingVoyage, reqVO.getBookingVoyage());
        queryWrapper.eq(SoDO::getBookingVessel, reqVO.getBookingVessel());
        queryWrapper.eq(SoDO::getPolCode, reqVO.getPolCode());
        return soMapper.selectList(queryWrapper);
    }
}
